#ifndef STATE_MACHINE_HPP
#define STATE_MACHINE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <assert.h>

#include "State.hpp"

#include <SmegTools/Debug/DebugNew.hpp>

namespace smeg {
    namespace core {

struct MessageInfo;

////////////////////////////////////////////////////////////
// State Machine Class
////////////////////////////////////////////////////////////
template < typename ENTITY >
class StateMachine
{
public:
    ////////////////////////////////////////////////////////////
    /// Constructor/Destructor
    ///
    ////////////////////////////////////////////////////////////
                        StateMachine( ENTITY* _pOwner = NULL ) :
        m_pOwner(_pOwner),
        m_pGlobalState(NULL),
        m_pCurrentState(NULL),
        m_pPreviousState(NULL)
    {}
    virtual             ~StateMachine()    {}

    ////////////////////////////////////////////////////////////
    /// Setters
    ///
    ////////////////////////////////////////////////////////////
    void                SetOwner( ENTITY* _pOwner ) {
        m_pOwner = _pOwner;
    }
    void                SetGlobalState( State< ENTITY >* _pGlobalState ) {
        m_pGlobalState = _pGlobalState;
    }

    ////////////////////////////////////////////////////////////
    /// Update the state machine
    ///
    ////////////////////////////////////////////////////////////
    void                Update() {
        if ( m_pGlobalState ) {
            m_pGlobalState->OnUpdate( m_pOwner );
        }

        if ( m_pCurrentState ) {
            m_pCurrentState->OnUpdate( m_pOwner );
        }
    }

    ////////////////////////////////////////////////////////////
    /// Change the state of the entity
    ///
    ////////////////////////////////////////////////////////////
    void                ChangeState( State< ENTITY >* _pNewState ) {
        assert( _pNewState );

        if ( m_pCurrentState ) {
            m_pCurrentState->OnExit( m_pOwner );
        }

        m_pPreviousState    = m_pCurrentState;
        m_pCurrentState     = _pNewState;

        _pNewState->OnEnter( m_pOwner );
    }

    ////////////////////////////////////////////////////////////
    /// Handle an incoming message, pass it to the current and global state
    ///
    ////////////////////////////////////////////////////////////
    bool                HandleMessage( const MessageInfo& _msg ) {
        if ( m_pCurrentState && m_pCurrentState->HandleMessage( m_pOwner, _msg ) ) {
            return true;
        }
        
        if ( m_pGlobalState && m_pGlobalState->HandleMessage( m_pOwner, _msg ) ) {
            return true;
        }

        return false;
    };
    
    ////////////////////////////////////////////////////////////
    /// Revert to the previous state
    ///
    ////////////////////////////////////////////////////////////
    void                RevertToPreviousState() {
        ChangeState( m_pPreviousState );
    }
    
    ////////////////////////////////////////////////////////////
    /// Return whether the the state given in parameter is the same as the current state.
    /// We test the pointer value of the state because they are singleton.
    ///
    ////////////////////////////////////////////////////////////
    bool                IsInState( const State<ENTITY>* _pState ) {
        return m_pCurrentState == _pState;
    }
    
    ////////////////////////////////////////////////////////////
    /// Return whether the the state given in parameter is the same as the last state.
    /// We test the pointer value of the state because they are singleton.
    ///
    ////////////////////////////////////////////////////////////
    bool                IsLastState( const State<ENTITY>* _pState ) {
        return m_pPreviousState == _pState;
    }

private:
    ENTITY*             m_pOwner;
    
    State< ENTITY >*    m_pCurrentState;
    State< ENTITY >*    m_pGlobalState;
    State< ENTITY >*    m_pPreviousState;
};

    } // namespace core
} // namespace smeg

#include <SmegTools/Debug/DebugNewOff.hpp>

#endif // STATE_MACHINE_HPP